package com.cdeledu.thread3.c7hookexception.uncaughtException;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 根据ThreadDemo、SubmitDemo、ExecuteDemo，针对提交给线程池的任务可能会抛出异常这一问题，主要有以下两种处理思路：
 * 在提交的任务当中自行try
 * ...catch，但这里有个不好的地方就是如果你会提交多种类型的任务到线程池中，每种类型的任务都需要自行将异常try...catch住
 * ，比较繁琐。而且如果你只是catch(Exception
 * e)，可能依然会漏掉一些包括Error类型的异常，那为了保险起见，可以考虑catch(Throwable t)。
 * 自行实现线程池的afterExecute方法，或者实现Thread的UncaughtExceptionHandler接口。
 *
 * 下面给出我个人创建线程池的一个示例，供大家参考：
 *
 * @author zhangsulei
 *
 */
public class RightDemo {

	private static final int DEFAULT_QUEUE_SIZE = 10;
	private static final int DEFAULT_CORE_POOL_SIZE = 10;
	private static final int DEFAULT_MAX_POOL_SIZE = 10;
	private static Logger logger = LoggerFactory.getLogger(RightDemo.class);

	public static void main(String[] args) {
		BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(DEFAULT_QUEUE_SIZE);
		ExecutorService statisticsThreadPool = new ThreadPoolExecutor(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAX_POOL_SIZE, 60, TimeUnit.SECONDS, queue, new ThreadFactory() {
			@Override
			public Thread newThread(Runnable r) {
				Thread thread = new Thread(r);
				thread.setUncaughtExceptionHandler((t, e) -> {
					e.printStackTrace(); // 如果你把这一行注释掉，这个程序将不会抛出任何异常.
				});
				System.out.println("create: " + thread.getName());
				return thread;
			}
		}, (r, executor) -> {
			if (!executor.isShutdown()) {
				logger.warn("statisticsThreadPool is too busy! waiting to insert task to queue! ");
			}
		}) {
			@Override
			protected void afterExecute(Runnable r, Throwable t) {
				super.afterExecute(r, t);
				if (t == null && r instanceof Future<?>) {
					try {
						Future<?> future = (Future<?>) r;
						future.get();
					} catch (CancellationException ce) {
						t = ce;
					} catch (ExecutionException ee) {
						t = ee.getCause();
					} catch (InterruptedException ie) {
						Thread.currentThread().interrupt(); // ignore/reset
					}
				}
				if (t != null) {
					logger.error("statisticsThreadPool error msg: {}", t.getMessage(), t);
				}
			}
		};

		statisticsThreadPool.execute(() -> {

		});
	}

}
